﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using PetaPoco;

using Happy.ExtentionMethods;

namespace Happy.Query.PetaPoco
{
    /// <summary>
    /// 基于 PetaPoco 的查询服务。
    /// </summary>
    public class QuerySource<T> : IQuerySource<T>
    {
        private readonly string _connectionStringName;
        private readonly string _connectionString;
        private readonly string _providerName;
        private readonly string _fromClause;

        /// <summary>
        /// 构造方法。
        /// </summary>
        public QuerySource(string connectionStringName)
        {
            connectionStringName.MustNotNullAndNotWhiteSpace("connectionStringName");

            _connectionStringName = connectionStringName;
            _fromClause = typeof(T).Name.ToPluralize();
        }

        /// <summary>
        /// 构造方法。
        /// </summary>
        public QuerySource(string connectionStringName, string fromClause)
        {
            connectionStringName.MustNotNullAndNotWhiteSpace("connectionStringName");
            fromClause.MustNotNullAndNotWhiteSpace("fromClause");

            _connectionStringName = connectionStringName;
            _fromClause = fromClause;
        }

        /// <summary>
        /// 构造方法。
        /// </summary>
        public QuerySource(string connectionString, string providerName, string fromClause)
        {
            connectionString.MustNotNullAndNotWhiteSpace("connectionString");
            providerName.MustNotNullAndNotWhiteSpace("providerName");
            fromClause.MustNotNullAndNotWhiteSpace("fromClause");

            _connectionString = connectionString;
            _providerName = providerName;
            _fromClause = fromClause;
        }

        /// <inheritdoc />
        public PageResult<T> Page(QueryArgument query, long page, long itemsPerPage)
        {
            query.MustNotNull("query");

            using (var db = this.CreateDatabase())
            {
                return this.Page(db, query, page, itemsPerPage);
            }
        }

        /// <summary>
        /// 执行 Page 查询。
        /// </summary>
        protected virtual PageResult<T> Page(Database db, QueryArgument query, long page, long itemsPerPage)
        {
            var sql = this.CreateSqlFromQuery(query);

            return this.CreatePageResult(db.Page<T>(page, itemsPerPage, sql));
        }

        /// <inheritdoc />
        public IEnumerable<T> SkipTake(QueryArgument query, long skip, long take)
        {
            query.MustNotNull("query");

            using (var db = this.CreateDatabase())
            {
                return this.SkipTake(db, query, skip, take);
            }
        }

        /// <summary>
        /// 执行 Fetch 查询。
        /// </summary>
        protected virtual IEnumerable<T> SkipTake(Database db, QueryArgument query, long skip, long take)
        {
            var sql = this.CreateSqlFromQuery(query);
     
            return db.SkipTake<T>(skip, take, sql);
        }

        /// <inheritdoc />
        public IEnumerable<T> Fetch(QueryArgument query)
        {
            query.MustNotNull("query");

            using (var db = this.CreateDatabase())
            {
                return this.Fetch(db, query);
            }
        }

        /// <summary>
        /// 执行 Fetch 查询。
        /// </summary>
        protected virtual IEnumerable<T> Fetch(Database db, QueryArgument query)
        {
            var sql = this.CreateSqlFromQuery(query);

            return db.Fetch<T>(sql);
        }

        /// <inheritdoc />
        public T SingleOrDefault(QueryArgument query)
        {
            query.MustNotNull("query");

            using (var db = this.CreateDatabase())
            {
                return this.SingleOrDefault(db, query);
            }
        }

        /// <summary>
        /// 执行 SingleOrDefault 查询。
        /// </summary>
        protected virtual T SingleOrDefault(Database db, QueryArgument query)
        {
            var sql = this.CreateSqlFromQuery(query);

            return db.SingleOrDefault<T>(sql);
        }

        /// <inheritdoc />
        public T SingleOrDefault(object id, bool includeRelation = true)
        {
            id.MustNotNull("id");

            using (var db = this.CreateDatabase())
            {
                return this.SingleOrDefault(db, id, includeRelation);
            }
        }

        /// <summary>
        /// 执行 SingleOrDefault 查询。
        /// </summary>
        protected virtual T SingleOrDefault(Database db, object id, bool includeRelation = true)
        {
            var query = QueryArgument.Create(new { Id = id });
            var sql = this.CreateSqlFromQuery(query);

            return db.SingleOrDefault<T>(sql);
        }

        /// <summary>
        /// 创建 PetaPoco.Database。
        /// </summary>
        protected Database CreateDatabase()
        {
            if (_connectionStringName != null)
            {
                return new Database(_connectionStringName);
            }

            return new Database(_connectionString, _providerName);
        }

        private Sql CreateSqlFromQuery(QueryArgument query)
        {
            var sql = Sql.Builder;

            if (query.Columns != null && query.Columns.Any())
            {
                sql.Select(query.Columns.ToArray());
            }
            else
            {
                sql.Select("*");
            }

            sql.Append(string.Format("FROM {0}", _fromClause));

            if (query.WhereClauses != null)
            {
                foreach (var whereClause in query.WhereClauses)
                {
                    if (!string.IsNullOrWhiteSpace(whereClause.Clause))
                    {
                        sql.Where(whereClause.Clause, whereClause.Arguments);
                    }
                }
            }

            if (query.OrderClauses.Any())
            {
                foreach (var orderClause in query.OrderClauses)
                {
                    sql.OrderBy(orderClause);
                }
            }
            else if (this.DefaultOrderClauses.Any())
            {
                foreach (var orderClause in this.DefaultOrderClauses)
                {
                    sql.OrderBy(orderClause);
                }
            }

            return sql;
        }

        /// <summary>
        /// 创建 PageResult{T}。
        /// </summary>
        protected PageResult<T> CreatePageResult(Page<T> page)
        {
            return new PageResult<T>
            {
                CurrentPage = page.CurrentPage,
                Items = page.Items,
                ItemsPerPage = page.ItemsPerPage,
                TotalItems = page.TotalItems,
                TotalPages = page.TotalPages
            };
        }

        /// <summary>
        /// 默认排序语句。
        /// </summary>
        protected virtual string[] DefaultOrderClauses
        {
            get
            {
                return new string[] { };
            }
        }
    }
}
